package com.ruoyi.system.service.impl;

import com.ruoyi.common.config.WxAppConfig;
import com.ruoyi.common.config.WxPaymentConfig;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.SecureUtil;
import com.ruoyi.common.utils.XmlUtils;
import com.ruoyi.common.config.WxPayConfig;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.system.service.IWechatPayService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.*;
import org.slf4j.Logger;

@Service
public class WechatPayServiceImpl implements IWechatPayService {

    private static final Logger log = LoggerFactory.getLogger(WechatPayServiceImpl.class);

    @Resource
    private WxPayConfig wxPayConfig; // 微信支付配置

    @Resource
    private WxAppConfig wechatMiniappConfig; // 小程序配置（需读取wechat.miniapp.appid）

    @Resource
    private WxPaymentConfig wxPaymentConfig;

    @Override
    public Map<String, String> getWechatPayParams(
            String orderNo, Integer totalFee, String openId) throws Exception {

        // 2. 构造微信统一下单参数（XML格式）
        Map<String, String> unifiedOrderParams = new HashMap<>();
        // 小程序AppID
        unifiedOrderParams.put("appid", wxPaymentConfig.getAppid());
        // 商户号
        unifiedOrderParams.put("mch_id", wxPaymentConfig.getMchId());
        // 支付回调地址（必填）
        unifiedOrderParams.put("notify_url", wxPaymentConfig.getNotifyDomain());
        // 交易类型（小程序固定为JSAPI，必填）
        unifiedOrderParams.put("trade_type", "JSAPI");
        // 随机字符串（32位以内）
        unifiedOrderParams.put("nonce_str", generateNonceStr(32));
        // 商品描述（必填）
        unifiedOrderParams.put("body", "商品描述（如：XX订单支付）");
        // 客户端IP（可从请求中获取，如request.getRemoteAddr()）
        unifiedOrderParams.put("spbill_create_ip", IpUtils.getIpAddr());
        // 支付金额（分，必填）
        unifiedOrderParams.put("total_fee", String.valueOf(totalFee));
        // 订单号（唯一，必填）
        unifiedOrderParams.put("out_trade_no", orderNo);
        // 用户OpenID（JSAPI必填）
        unifiedOrderParams.put("openid", openId);

        // 2. 生成V2签名（统一下单使用MD5）
        String signV2 = generateV2Sign(unifiedOrderParams, wxPaymentConfig.getApiV2Key());
        unifiedOrderParams.put("signV2", signV2);

        // 3. 生成统一下单签名（根据微信规则）
//        String signV3 = generateSign(unifiedOrderParams, wxPaymentConfig.getApiV3Key(), wxPaymentConfig.getSignType());
//        unifiedOrderParams.put("signV3", signV3); // 添加签名到参数中

        // 4. 调用微信统一下单接口（POST XML数据）
        String xmlParams = XmlUtils.mapToXml(unifiedOrderParams); // 将Map转换为XML
        String responseXml = HttpUtils.sendPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi", xmlParams); // 发送POST请求

        // 4. 增强响应处理
        if(responseXml.trim().isEmpty()) {
            throw new Exception("统一下单接口返回空响应");
        }
        log.info("统一下单原始响应：" + responseXml);

        // 将返回的XML转换为Map
        Map<String, String> responseMap = XmlUtils.xmlToMap(responseXml);

        // 5. 校验统一下单结果
        if (!"SUCCESS".equals(responseMap.get("return_code")) || !"SUCCESS".equals(responseMap.get("result_code"))) {
            throw new Exception("统一下单失败：" + responseMap.get("return_msg") + "（" + responseMap.get("err_code_des") + "）");
        }

        // 6. 获取prepay_id（统一下单成功后返回）
        String prepayId = responseMap.get("prepay_id");
        if (prepayId == null || prepayId.isEmpty()) {
            throw new Exception("未获取到prepay_id");
        }

        // 7. 生成前端所需的支付参数（用于wx.requestPayment）
        // Map<String, String> payParams = new LinkedHashMap<>();
        Map<String, String> payParams = new HashMap<>();
        // 当前时间戳（秒，必填）
        payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        // 随机字符串（必填）
        payParams.put("nonceStr", generateNonceStr(32));
        // 格式固定为"prepay_id=xxx"（必填）
        payParams.put("package", "prepay_id=" + prepayId);
        // 签名类型（与统一下单一致，必填）
        payParams.put("signType", "RSA");

        // 7. 生成RSA签名（严格按照微信规范）
        payParams.put("paySign", generatePaySign(
                wxPaymentConfig.getAppid(),
                payParams.get("timeStamp"),
                payParams.get("nonceStr"),
                payParams.get("package") // 完整package字符串
        ));

//        // 8. 生成V3签名（关键变更点）
//        String paySign = generateV3Sign(
//                wxPaymentConfig.getAppid(),
//                payParams.get("timeStamp"),
//                payParams.get("nonceStr"),
//                payParams.get("package"),
//                // 获取私钥
//                wxPaymentConfig.getPrivateKey(wxPaymentConfig.getPrivateKeyPath())
//        );
//        payParams.put("paySign", paySign);

        return payParams;
    }

//        // 8. 生成paySign（前端支付签名，需再次签名）
//        Map<String, String> signParams = new HashMap<>();
//        signParams.put("appId", wechatMiniappConfig.getAppId()); // 小程序AppID
//        signParams.put("timeStamp", payParams.get("timeStamp")); // 时间戳
//        signParams.put("nonceStr", payParams.get("nonceStr")); // 随机字符串
//        signParams.put("package", payParams.get("package")); // package参数
//        signParams.put("signType", payParams.get("signType")); // 签名类型
//        String paySign = generateSign(signParams, wxPayConfig.getMchKey(), wxPayConfig.getSignType());
//        payParams.put("paySign", paySign); // 添加paySign到参数中
//
//        // 返回前端所需的支付参数
//        return payParams;
//    }


    // 2. 新增随机字符串生成方法
    private String generateNonceStr(int maxLength) {
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < maxLength; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        return sb.toString();
    }

    // 3. 新增V3签名方法
    private String generateV3Sign(
            String appId, String timeStamp, String nonceStr, String packageValue, PrivateKey privateKey) throws Exception {
        // 拼接待签名字符串（四行结构）
        String signData = appId + "\n"
                + timeStamp + "\n"
                + nonceStr + "\n"
                + packageValue.split("=")[1] + "\n"; // 只取prepay_id值

        // 使用商户私钥进行SHA256withRSA签名
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(signData.getBytes(StandardCharsets.UTF_8));

        // 返回Base64编码的签名值
        return Base64.getEncoder().encodeToString(signature.sign());
    }

    // 生成小程序支付签名 (RSA-SHA256)
    private String generatePaySign(String appId, String timeStamp, String nonceStr, String packageValue)
            throws Exception {

        // 1. 严格按照微信格式拼接签名串
        String signData = appId + "\n"
                + timeStamp + "\n"
                + nonceStr + "\n"
                + packageValue + "\n"; // 包含完整"prepay_id=xxx"

        // 2. 获取商户私钥
        PrivateKey privateKey = wxPaymentConfig.getPrivateKey(wxPaymentConfig.getPrivateKeyPath());
        if (privateKey == null) {
            throw new Exception("商户私钥未配置");
        }

        // 3. SHA256withRSA签名
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(signData.getBytes(StandardCharsets.UTF_8));

        // 4. Base64编码
        return Base64.getEncoder().encodeToString(signature.sign());
    }

    // 生成V2签名 (统一下单使用)
    private String generateV2Sign(Map<String, String> params, String mchKey) {
        StringBuilder sb = new StringBuilder();
        params.forEach((k, v) -> {
            if (v != null && !v.isEmpty() && !"sign".equals(k)) {
                sb.append(k).append("=").append(v).append("&");
            }
        });
        sb.append("key=").append(mchKey);
        return SecureUtil.md5(sb.toString()).toUpperCase(); // V2接口使用MD5
    }


    /**
     * 生成微信支付签名（遵循微信签名规则）
     * @param params 待签名的参数集合
     * @param key 商户密钥（wxpay.mch_key）
     * @param signType 签名类型（如MD5、HMAC-SHA256）
     * @return 签名结果（大写）
     */
    private String generateSign(Map<String, String> params, String key, String signType) {
        // 1. 过滤空值参数（微信要求：空值参数不参与签名）
        Map<String, String> filteredParams = new HashMap<>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
                filteredParams.put(entry.getKey(), entry.getValue());
            }
        }

        // 2. 将参数按字典序排序（微信要求：键名ASCII码从小到大排序）
        List<String> sortedKeys = new ArrayList<>(filteredParams.keySet());
        Collections.sort(sortedKeys);

        // 3. 拼接成"key=value&key=value"的字符串
        StringBuilder sb = new StringBuilder();
        for (String k : sortedKeys) {
            sb.append(k).append("=").append(filteredParams.get(k)).append("&");
        }

        // 4. 添加商户密钥（微信要求：最后拼接"key=商户密钥"）
        sb.append("key=").append(key);

        // 5. 根据签名类型生成签名（MD5或HMAC-SHA256）
        if ("HMAC-SHA256".equalsIgnoreCase(signType)) {
            return SecureUtil.hmacSha256(sb.toString(), key).toUpperCase();
        } else { // 默认MD5
            return SecureUtil.md5(sb.toString()).toUpperCase();
        }
    }
}
